package com.inspur.edp.bef.bemanager.codegenerator;


import com.inspur.edp.bef.bemanager.codegenerator.actions.JavaBaseCommonCompCodeGen;
import com.inspur.edp.bef.bemanager.generatecomponent.ComponentGenUtil;
import com.inspur.edp.bef.bemanager.util.CheckInfoUtil;
import com.inspur.edp.bef.bemanager.util.ComponentExtendProperty;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.common.BizEntityJsonConst;
import com.inspur.edp.bef.bizentity.common.OperationConvertUtils;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityErrorCodeEnum;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityException;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.bef.bizentity.operation.Determination;
import com.inspur.edp.bef.bizentity.operation.TccAction;
import com.inspur.edp.bef.bizentity.operation.Validation;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.TccSettingElement;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.collection.CommonValCollection;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.operation.CommonDetermination;
import com.inspur.edp.cef.designtime.api.operation.CommonValidation;
import com.inspur.edp.cef.variable.dtgenerator.vardtmGenerate.javageneratecmpcode.JavaCommonDeterminationGenerator;
import com.inspur.edp.cef.variable.dtgenerator.vardtmGenerate.javageneratecmpcode.JavaIBaseCompCodeGen;
import com.inspur.edp.jittojava.context.GenerateService;
import com.inspur.edp.lcm.fs.api.IFsService;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspProject;
import com.inspur.edp.lcm.metadata.api.service.FileService;
import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;

public class JavaCodeFileGenerator {
    private String relativePath;
    private GspBusinessEntity be;
    private String compAssemblyName;
    private IFsService iFsService;
    private FileService fsService;
    private static final String javaCodeFileExtension = ".java";
    private ArrayList<ComponentExtendProperty> extendProperties;
    /**
     * 创建文件路径
     *
     * @param metadata
     */
    public JavaCodeFileGenerator(GspMetadata metadata) {
        this();
        this.relativePath = metadata.getRelativePath();
        this.be = (GspBusinessEntity) metadata.getContent();
        this.compAssemblyName = ComponentGenUtil.GetComponentNamespace(relativePath);
    }

    public JavaCodeFileGenerator(String path, GspBusinessEntity be) {
        this();
        this.relativePath = path;
        this.be = be;
        this.compAssemblyName = ComponentGenUtil.GetComponentNamespace(relativePath);
    }

    public JavaCodeFileGenerator() {
        this.iFsService = SpringBeanUtils.getBean(IFsService.class);
        this.fsService = SpringBeanUtils.getBean(FileService.class);
        this.extendProperties = new ArrayList<>();
    }

    public void generate(ArrayList<String> actionList) {
        JavaGenerateBizMgrActions(actionList);
        JavaGenerateBizActions(actionList);
        JavaGenerateDeterminations(actionList);
        JavaGenerateValidations(actionList);
        JavaGenerateVariableDtms(actionList);
        javaGenerateTccActions(actionList);
        javaGenerateBeanConfigFile();
    }

    private static String mgrActionDirName = "BizActions";

    private void JavaGenerateBizMgrActions(ArrayList<String> actionList) {
        String path = JavaPrepareBizActionsDir(mgrActionDirName);

        for (BizOperation action : be.getCustomMgrActions()) {
            if(actionList.contains(action.getCode())){
                JavaBizMgrCodeGenerate(action, path, null);
            }
        }
    }

    private static String JavaBizActionDirName = "EntityActions";

    private void JavaGenerateBizActions(ArrayList<String> actionList) {
        //var path = JavaPrepareBizActionsDir(JavaBizActionDirName);
        java.util.ArrayList<GspBizEntityObject> nodes = be.getAllNodes();

        for (GspBizEntityObject node : nodes) {

            for (BizOperation action : node.getCustomBEActions()) {
                if(actionList.contains(action.getCode())){
                    String path = JavaPrepareDir(JavaBizActionDirName, node.getCode());
                    JavaBECodeGenerate(action, path, be.getMainObject());
                }
            }
        }
    }

    private static String JavaTccActionDirName = "TccActions";

    private void javaGenerateTccActions(ArrayList<String> actionList) {
        java.util.ArrayList<GspBizEntityObject> nodes = be.getAllNodes();
        for (GspBizEntityObject node : nodes) {
            for(TccSettingElement ele: node.getTccSettings()) {
                TccAction action = ele.getTccAction();
                if(actionList.contains(action.getCode())) {
                    String path = JavaPrepareDir(JavaTccActionDirName, node.getCode());
                    JavaBECodeGenerate(action, path, node);
                }
            }
        }
    }

    private static String JavaDtmDirName = "Determinations";

    private void JavaGenerateDeterminations(ArrayList<String> actionList) {
        for (GspBizEntityObject node : be.getAllNodes()) {
            for (BizOperation action : node.getDeterminations()) {
                if (actionList.contains(action.getCode())) {
                    String path = JavaPrepareDir(JavaDtmDirName, node.getCode());
                    JavaDtmCodeGenerate(action, path, node);
                }
            }

            generateCommonDtm(actionList, node, node.getDtmAfterCreate(), CefNames.DtmAfterCreate);
            generateCommonDtm(actionList, node, node.getAllDtmAfterModify(), CefNames.DtmAfterModify);
            generateCommonDtm(actionList, node, node.getAllDtmBeforeSave(), CefNames.DtmBeforeSave);
            generateCommonDtm(actionList, node, node.getDtmBeforeQuery(), BizEntityJsonConst.B4QueryDtm);
            generateCommonDtm(actionList, node, node.getDtmAfterQuery(), BizEntityJsonConst.AftQueryDtm);
            generateCommonDtm(actionList, node, node.getDtmCancel(), BizEntityJsonConst.DtmCancel);
            generateCommonDtm(actionList, node, node.getDtmBeforeRetrieve(), BizEntityJsonConst.B4RetrieveDtm);
            generateCommonDtm(actionList, node, node.getDtmAfterLoading(), BizEntityJsonConst.AftLoadingDtm);
        }
    }

    private void generateCommonDtm(List<String> actionList, GspBizEntityObject obj,
        CommonDtmCollection dtmCollection, String commonDtmType) {
        if (dtmCollection == null) {
            return;
        }
        for(CommonDetermination dtm : dtmCollection) {
            if (!actionList.contains(dtm.getCode()) || dtm.getIsRef() || !dtm.getIsGenerateComponent()
                || obj.getDeterminations().findById(dtm.getID()) != null) {
                continue;
            }
            String path = JavaPrepareDir(JavaDtmDirName, obj.getCode());
            Determination action = OperationConvertUtils.convertToDtm(dtm, commonDtmType, obj);
            JavaDtmCodeGenerate(action, path, obj);
        }
    }

    private static String JavaValidationDirName = "Validations";

    private void JavaGenerateValidations(ArrayList<String> actionList) {
        //var path = JavaPrepareDir(JavaValidationDirName);

        for (GspBizEntityObject node : be.getAllNodes()) {

            for (BizOperation action : node.getValidations()) {
                if (actionList.contains(action.getCode())) {
                    String path = JavaPrepareDir(JavaValidationDirName, node.getCode());
                    JavaValCodeGenerate(action, path, node);
                }
            }

            generateCommonVal(actionList, node, node.getValAfterSave(), BizEntityJsonConst.ValidationAfterSave);
            generateCommonVal(actionList, node, node.getallValBeforeSave(), CefNames.ValBeforeSave);
            generateCommonVal(actionList, node, node.getAllValAfterModify(), CefNames.ValAfterModify);
        }
    }

    private void generateCommonVal(List<String> actionList, GspBizEntityObject obj,
        CommonValCollection collection, String commonType) {
        if (collection == null) {
            return;
        }
        for(CommonValidation val : collection) {
            if (!actionList.contains(val.getCode()) || val.getIsRef() || !val.getIsGenerateComponent()
                || obj.getValidations().findById(val.getID()) != null) {
                continue;
            }
            String path = JavaPrepareDir(JavaValidationDirName, obj.getCode());
            Validation action = OperationConvertUtils.convertToVal(val, commonType, obj);
            JavaValCodeGenerate(action, path, obj);
        }
    }

    private static String determinationDirName = "VarDeterminations";

    private void JavaGenerateVariableDtms(ArrayList<String> actionList) {
        if (be.getVariables() == null) {
            return;
        }
        String path = JavaPrepareDir(determinationDirName, be.getCode());

        JavaGenerateVariableDtms(be.getVariables().getDtmAfterCreate(), path,actionList);
        JavaGenerateVariableDtms(be.getVariables().getDtmAfterModify(), path,actionList);
        JavaGenerateVariableDtms(be.getVariables().getDtmBeforeSave(), path,actionList);
    }

    private String GetMetaProjName(GspProject projInfo) {
        String boProjName = projInfo.getMetadataProjectName().toLowerCase();
        return boProjName.substring(0, 0) + boProjName.substring(0 + boProjName.indexOf('-') + 1);
    }

    private String GetJavaCompModulePath() {
        String generatingAssembly = be.getDotnetGeneratingAssembly().replace(".", "\\");

        MetadataProjectService service = SpringBeanUtils.getBean(MetadataProjectService.class);

        String compModulePath = service.getJavaCompProjectPath(relativePath);

        //TODO toLowerCase 需要修改
        String compositePath = CheckInfoUtil.getCombinePath(compModulePath, "com", generatingAssembly.toLowerCase());

//		String compositePath = String.Concat(compModulePath, "\\com\\", generatingAssembly.toLowerCase());
        return compositePath;

    }

    private String JavaPrepareDir(String actionDirName, String codeDir) {
        String path = CheckInfoUtil.getCombinePath(GetJavaCompModulePath(), codeDir.toLowerCase(), actionDirName.toLowerCase());
//		String path = Path.Combine(GetJavaCompModulePath(), codeDir.toLowerCase(), actionDirName.toLowerCase());
        if (!fsService.isDirectoryExist(path)) {
            fsService.createDirectory(path);
        }
        return path;
    }

    private String JavaPrepareBizActionsDir(String actionDirName) {

        String path = CheckInfoUtil.getCombinePath(GetJavaCompModulePath(), actionDirName.toLowerCase());

//		var path = Path.Combine(GetJavaCompModulePath(), actionDirName.toLowerCase());
        if (!fsService.isDirectoryExist(path)) {
            fsService.createDirectory(path);
        }
        return path;
    }


    private void JavaBizMgrCodeGenerate(BizOperation op, String dirPath, GspBizEntityObject belongNode) {
        if (!op.getIsRef() && op.getIsGenerateComponent()) {
            JavaGenerateSingleFile(op, dirPath, false, null);
        }
    }

    //ORIGINAL LINE: private void JavaDtmCodeGenerate(BizOperation op, string dirPath, GspBizEntityObject belongNode = null)
    private void JavaDtmCodeGenerate(BizOperation op, String dirPath, GspBizEntityObject belongNode) {
        if (!op.getIsRef() && op.getIsGenerateComponent()) {
            JavaGenerateSingleFile(op, dirPath, !belongNode.getIsRootNode(), belongNode.getCode());
        }
    }

    //ORIGINAL LINE: private void JavaValCodeGenerate(BizOperation op, string dirPath, GspBizEntityObject belongNode = null)
    private void JavaValCodeGenerate(BizOperation op, String dirPath, GspBizEntityObject belongNode) {
        if (!op.getIsRef() && op.getIsGenerateComponent()) {
            JavaGenerateSingleFile(op, dirPath, !belongNode.getIsRootNode(), belongNode.getCode());
        }
    }

    //ORIGINAL LINE: private void JavaBECodeGenerate(BizOperation op, string dirPath, GspBizEntityObject belongNode = null)
    private void JavaBECodeGenerate(BizOperation op, String dirPath, GspBizEntityObject belongNode) {
        if (!op.getIsRef() && op.getIsGenerateComponent()) {
            JavaGenerateSingleFile(op, dirPath, !belongNode.getIsRootNode(), belongNode.getCode());
        }
    }

    @Getter
    private String codeContent;

    //ORIGINAL LINE: private void JavaGenerateSingleFile(BizOperation op, string dirPath,GspBizEntityObject belongNode = null)
    private void JavaGenerateSingleFile(BizOperation op, String dirPath, boolean isChild, String nodeCode) {
        JavaBaseCommonCompCodeGen codeGen = !isChild ?
            JavaCmpCodeGeneratorFactory.JavaGetGenerator(be, op, compAssemblyName, relativePath) :
            JavaCmpCodeGeneratorFactory.JavaGetChildNodeGenerator(be, nodeCode, op, compAssemblyName, relativePath);

        String originalFilePath = CheckInfoUtil.getCombinePath(relativePath, ComponentGenUtil.ComponentDir, codeGen.GetCompName() + javaCodeFileExtension);
        String filePathExe = CheckInfoUtil.getCombinePath(dirPath, codeGen.GetCompName() + javaCodeFileExtension);
        //此两处判断用来兼容原来没有对应文件夹情形
        if (fsService.isFileExist(originalFilePath)) {
            JavaReplace(originalFilePath);
            return;
        }
        if ((fsService.isFileExist(filePathExe))) {
            JavaReplace(filePathExe);
            return;
        }
        codeContent = codeGen.Generate();
        iFsService.createFile(filePathExe, codeContent, StandardCharsets.UTF_8);
        ComponentExtendProperty extendProp = codeGen.getExtendProperty();
        if(extendProp != null && extendProp.getCefConfigBeanGenCode()!= null) {
            this.extendProperties.add(extendProp);
        }
    }

    public void createVarDtmJavaCodeFile(CommonDetermination dtm) {
        String path = JavaPrepareDir(determinationDirName, be.getCode());
        JavaGenerateVariableDtm(dtm, path);
    }

    public void createJavaCodeFile(BizOperation op, boolean isChild, String nodeCode) {
        String path;
        switch(op.getOpType()) {
            case BizMgrAction:
                path = JavaPrepareBizActionsDir(mgrActionDirName);
                break;
            case BizAction:
                path = JavaPrepareDir(JavaBizActionDirName, nodeCode);
                break;
            case TccAction:
                path = JavaPrepareDir(JavaTccActionDirName, nodeCode);
                break;
            case Validation:
                path = JavaPrepareDir(JavaValidationDirName, nodeCode);
                break;
            case Determination:
                path = JavaPrepareDir(JavaDtmDirName, nodeCode);
                break;
            default:
                throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_ENUM_NOTSUPPORT_0009, op.getOpType().toString());
        }
        JavaGenerateSingleFile(op, path, isChild, nodeCode);
        javaGenerateBeanConfigFile();
    }

    private void JavaGenerateVariableDtmFile(JavaIBaseCompCodeGen codeGen, String dirPath) {
        String originalFilePath = CheckInfoUtil.getCombinePath(relativePath, ComponentGenUtil.ComponentDir, codeGen.getCompName() + javaCodeFileExtension);
        String filePathExe = CheckInfoUtil.getCombinePath(dirPath, codeGen.getCompName() + javaCodeFileExtension);
        String filePathCommon = CheckInfoUtil.getCombinePath(dirPath, codeGen.getCompName() + "Ctor" + javaCodeFileExtension);

        if (fsService.isFileExist(originalFilePath)) {
            return;
        }
        //此处判断用来兼容文件夹下已经有对应的生成文件情形
        if ((fsService.isFileExist(filePathExe)) && (!fsService.isFileExist(filePathCommon))) {
            return;
        }
        if (!fsService.isFileExist(filePathExe)) {
            iFsService.createFile(filePathExe, codeGen.generateExecute());
        }
        // be动作执行GenerateCommon(),commonDtm不执行
        if (codeGen.getIsCommonGenerate()) {
            iFsService.createFile(filePathExe, codeGen.generateCommon());
        }
    }

    /**
     * 兼容原来情况，修改引用的程序集
     *
     * @param filePath
     */
    private void JavaReplace(String filePath) {
        String oldValue = "import com.inspur.Gsp.bef.entity.changeset;";
        String newValue = "import inspur.Gsp.cef.entity.changeset;";
        String content = null;
        try {
            content = fsService.fileRead(filePath);
        } catch (IOException e) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0084, e, filePath);
        }
        if (!content.contains(oldValue)) {
            return;
        }
        codeContent = content.replace(oldValue, newValue);
        fsService.fileUpdate(filePath, codeContent);
    }

    private void JavaGenerateVariableDtms(CommonDtmCollection dtms, String dirPath,ArrayList<String> actionList) {

        for (CommonDetermination dtm : dtms) {
            if (dtm.getIsRef() || !dtm.getIsGenerateComponent() || !actionList.contains(dtm.getCode())) {
                continue;
            }
            JavaGenerateVariableDtm(dtm, dirPath);
        }
    }

    private void JavaGenerateVariableDtm(CommonDetermination dtm, String dirPath) {
        JavaCommonDeterminationGenerator gen = new JavaCommonDeterminationGenerator(be, dtm, compAssemblyName, relativePath);
        JavaGenerateVariableDtmFile(gen, dirPath);
    }

    private void javaGenerateBeanConfigFile() {
        if(this.extendProperties.size() == 0) {
            return;
        };
        String filePath = CheckInfoUtil.getCombinePath(GetJavaCompModulePath(), be.getCode()+ JavaCompCodeNames.CefConfigFileSuffix + javaCodeFileExtension);
        JavaBeanConfigGenerator beanConfigGen = new JavaBeanConfigGenerator(be, this.extendProperties, compAssemblyName);
        if (fsService.isFileExist(filePath)) {
            String content = null;
            try {
                content = fsService.fileRead(filePath);
            } catch (IOException e) {
                throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0084, e, filePath);
            }
            fsService.fileUpdate(filePath, beanConfigGen.update(content),false);
        } else {
            iFsService.createFile(filePath, beanConfigGen.generate());
            addSpringFactoriesProperty();
        }
    }
    private void addSpringFactoriesProperty() {
        GenerateService service= SpringBeanUtils.getBean(GenerateService.class);
        MetadataProjectService servicePath = SpringBeanUtils.getBean(MetadataProjectService.class);
        String compModulePath = servicePath.getJavaCompProjectPath(relativePath);
        String beanConfigPath = JavaCodeGeneratorUtil.ConvertImportPackage(be.getComponentAssemblyName())+"."+be.getCode()+JavaCompCodeNames.CefConfigFileSuffix;
        service.addProperties(compModulePath, JavaCompCodeNames.SPRING_FACTORIES_PROPERTYKEY,beanConfigPath);
    }
}
